﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Common.Utils;
using Common.Utils.Helper;
using Game.Kernel;
using Game.Logic.Data;
using Game.Logic.Events;
using UIFramework;
using NetFramework;
using Sproto;

namespace Game.Logic.Login
{
    public class LoginModel : GameUIModel
    {
        private GameStatus m_status = GameStatus.Invalid;

        public GameStatus Status { get => m_status; protected set => m_status = value; }

        public GameUserData GameUserData { private set; get; }
        public GameServerData GameServerData { private set; get; }

        public string Account { private set; get; }
        public string Password { private set; get; }

        public bool IsRegister { private set; get; }
        public bool ReadyToLogin { private set; get; }
        public bool IsHandShake { private set; get; }


        LoginModel()
        {
            GameUserData = GetGameData<GameUserData>(GameDataType.GameUser);
            GameServerData = GetGameData<GameServerData>(GameDataType.GameServer);
            InitLoginStatus();
            InitLoginData();
        }

        // 初始化数据
        private void InitLoginData()
        {
            Account = GameUserData.UserConfig.GetField("Account");
            Password = GameUserData.UserConfig.GetField("Password");
            IsRegister = false;
            IsHandShake = false;
        }

        #region GameStatus Interface
        private void InitLoginStatus()
        {
            Status = ClientKernel.Instance.GameController.GameStatus;
            ClientKernel.Instance.GameController.RegisterGameStatusUpdateHanler(OnUpdateGameStatus);
        }

        public virtual void OnUpdateGameStatus(GameStatus _cur, GameStatus _pre)
        {
            Status = _cur;
            switch (Status)
            {
                case GameStatus.EnterLogin:
                    Net_RequestHandshake();
                    break;
                default:
                    break;
            }
        }
        #endregion


        #region Model Event Interface
        private void DispatchGameUserData(params object[] _params)
        {
            DispatchModelEvent(GameModelEvent.Create(GameDataType.GameUser, GameUserData, _params));
        }

        private void DispatchEventParams(params object[] _params)
        {
            DispatchModelEvent(GameModelEvent.Create(_params));
        }

        protected override void OnLinkView()
        {
            DispatchGameUserData(IsHandShake);
        }

        protected override void OnUnlinkView()
        {

        }
        #endregion


        #region Model Interface
        private bool OnHandlerLoginResult(long opcode, string opmsg, List<string> opargs)
        {



            return true;
        }

        private void OnAuthSuccess()
        {
            NetworkManager.Instance.Disconnect();
            CoroutineController.Instance.StartCoroutine(OnPrepareToConnectGate()); 
        }

        IEnumerator OnPrepareToConnectGate()
        {
            yield return new WaitForSeconds(0.01f);
            var server = GameServerData.GetServer();
            NetworkManager.Instance.Connect(server.Host, (uint)server.Port, () =>
            {
                Debug.Log("Login gate");
                SPNetMsg msg = new SPNetMsg();
                msg.ProtoType = (ushort)MessageType.Game;
                msg.ProtoName = "login";
                msg.Data = new SprotoObject(msg.ProtoName);
                msg.Data["token"] = GameServerData.Token;
                NetworkManager.Instance.Send(msg, (SprotoObject _response) =>
                {
                    Debug.Log("recive watchdog");
                    NetworkManager.Instance.StartSendHearbeat();

                    NetworkManager.Instance.Send(msg, (SprotoObject __response) =>
                    {
                        Debug.Log("recive agent");
                        //NetworkManager.Instance.StartSendHearbeat();
                    });
                });
            });
        }

        public void CancelUserDataAccountInfo()
        {
            GameUserData.UserConfig.SetField("Account", null);
            GameUserData.UserConfig.SetField("Password", null);
            DispatchGameUserData();
        }

        private void UpdateUserDataAccountInfo()
        {
            GameUserData.UserConfig.SetField("Account", Account);
            GameUserData.UserConfig.SetField("Password", Password);
            GameUserData.Save();
            DispatchGameUserData();
        }
        #endregion


        #region Controller Interface
        public void OnLoginGame(string account = null, string password = null, bool isRegister = false)
        {

        }

        public void OnAuthAccount(string account = null, string password = null, bool isRegister = false)
        {
            if (!ReadyToLogin)
            {
                ReadyToLogin = true;
                IsRegister = isRegister;
                return;
            }

            if ((null == account && null == password) || (0 == account.Length && 0 == password.Length))
            {
                Account = GameUserData.UserConfig.GetField("Account");
                Password = GameUserData.UserConfig.GetField("Password");
            }
            else
            {
                Account = account;
                Password = password;
            }

            if (null == Account && null == Password)
            {
                Account = GameTools.GenerateStringGUID();
                Password = GameTools.GeneratePassword();
                Net_RequestRegister(Account, Password);
            }
            else
            {
                if ((0 == Account.Length && 0 != Password.Length) || (0 != Account.Length && 0 == Password.Length))
                {
                    //TODO 显示用户名或密码为空
                    return;
                }

                if (isRegister || IsRegister)
                    Net_RequestRegister(Account, Password);
                else
                    Net_RequestAuth(Account, Password);
            }
        }
        #endregion


        #region Net Request
        private void Net_RequestHandshake()
        {
            string clientkey = GameTools.Base64EncodeFromBytes(GameTools.DHExchange(GameServerData.ClientKey));

            SPNetMsg msg = new SPNetMsg();
            msg.ProtoType = (ushort)MessageType.Login;
            msg.ProtoName = "handshake";
            msg.Data = new SprotoObject(msg.ProtoName);
            msg.Data["client_key"] = clientkey;

            // Debug.LogFormat("Net_RequestHandshake send");
            NetworkManager.Instance.Send(msg, Net_ResponseHandshake);
        }

        private void Net_ResponseHandshake(SprotoObject _response)
        {
            IsHandShake = true;
            DispatchEventParams(IsHandShake);
            if (ReadyToLogin)
            {
                OnLoginGame(Account, Password);
            }
            else
            {
                ReadyToLogin = true;
            }
        }

        private void Net_RequestAuth(string account = null, string password = null)
        {
            if (null == GameServerData.Secret)
                return;

            string base64account = GameTools.Base64Encode(account);
            string base64password = GameTools.Base64Encode(password);
            string accountInfo = string.Format("{0}@{1}@{2}", base64account, base64password, TimeHelper.GetCurrentTimeStamp().ToString());
            accountInfo = GameTools.Base64EncodeFromBytes(GameTools.DesEncrypt(accountInfo, GameServerData.Secret));

            SPNetMsg msg = new SPNetMsg();
            msg.ProtoType = (ushort)MessageType.Login;
            msg.ProtoName = "auth";
            msg.Data = new SprotoObject(msg.ProtoName);
            msg.Data["acc_secret"] = GameTools.Base64EncodeFromBytes(GameServerData.HMac);
            msg.Data["acc_info"] = accountInfo;
            NetworkManager.Instance.Send(msg, Net_ResponseAuth);
        }


        private void Net_ResponseAuth(SprotoObject _response)
        {
            SprotoObject obj = _response["code"];
            long opcode = obj["opcode"];
            string opmsg = obj["opmsg"];
            List<string> opargs = obj["opargs"];
            if (!OnHandlerLoginResult(opcode, opmsg, opargs))
                return;
            UpdateUserDataAccountInfo();
            OnAuthSuccess();
        }


        private void Net_RequestRegister(string account = null, string password = null, bool autoAuth = true)
        {
            string base64account = GameTools.Base64Encode(account);
            string base64password = GameTools.Base64Encode(password);
            string accountInfo = string.Format("{0}@{1}@{2}", base64account, base64password, TimeHelper.GetCurrentTimeStamp().ToString());
            accountInfo = GameTools.Base64EncodeFromBytes(GameTools.DesEncrypt(accountInfo, GameServerData.Secret));

            SPNetMsg msg = new SPNetMsg();
            msg.ProtoType = (ushort)MessageType.Login;
            msg.ProtoName = "register";
            msg.Data = new SprotoObject(msg.ProtoName);
            msg.Data["acc_secret"] = GameTools.Base64EncodeFromBytes(GameServerData.HMac);
            msg.Data["acc_info"] = accountInfo;
            msg.Data["auto_auth"] = autoAuth;
            NetworkManager.Instance.Send(msg, Net_ResponseRegister);
        }


        private void Net_ResponseRegister(SprotoObject _response)
        {
            SprotoObject obj = _response["code"];
            long opcode = obj["opcode"];
            string opmsg = obj["opmsg"];
            List<string> opargs = obj["opargs"];
            if (!OnHandlerLoginResult(opcode, opmsg, opargs))
                return;

            UpdateUserDataAccountInfo();
            OnAuthSuccess();
        }

        #endregion
    }
}
